81장. KMS — 데이터 암호화
이 장에서 말하고자 하는 것
데이터 보호의 두 축이 있다.
- 전송 중 암호화 (in transit) — TLS
- 저장 중 암호화 (at rest) — 디스크에 쓸 때 암호화
저장 중 암호화를 다루는 AWS 핵심 도구가
AWS KMS (Key Management Service)
다.
S3 · RDS · EBS · DynamoDB · Secrets Manager · CloudWatch Logs 등
거의 모든 데이터 저장 서비스가 KMS와 연동된다.
1. KMS의 기본
KMS는 암호화 키를 안전하게 만들고 관리 해주는 서비스다.
[KMS Key]
├─ 실제 키 값은 KMS 밖으로 절대 나가지 않음
└─ 호출자는 키 ID로 "암호화 해줘 / 복호화 해줘" 만 요청
키 값을 사람이 직접 다루지 않는 게 핵심이다.
2. 두 종류의 키
AWS Managed Key
AWS가 자동으로 만들고 회전한다 (예: aws/s3, aws/rds).
- 시작에 편하다
- 키 정책을 본인이 수정할 수 없다
Customer Managed Key (CMK)
본인이 만들고 관리한다.
- 키 정책 · 회전 주기 · 접근 권한을 직접 통제
- 키 삭제 (대기 기간 후) 가능
- 운영 환경의 표준
시작은 AWS Managed, 운영 자원은 CMK로 옮긴다
3. Envelope Encryption — 큰 데이터를 효율적으로
KMS API는 작은 데이터만 직접 암호화한다 (~4KB).
큰 데이터는 Envelope Encryption 패턴.
1. KMS에서 Data Key 발급
2. Data Key로 큰 데이터를 암호화 (애플리케이션 측에서)
3. Data Key 자체는 KMS Key로 암호화해 저장
대부분의 AWS 서비스 (S3 · EBS · RDS …) 가 내부적으로 이걸 자동으로 한다.
4. 키 회전
CMK는 자동 회전 옵션을 켤 수 있다.
365일마다 새 키 값으로 회전
옛 키 값은 그대로 보관 (옛 데이터 복호화 가능)
호출자는 키 ID만 가지고 있으면 변화를 느끼지 못한다.
운영 CMK는 자동 회전을 켜는 게 표준
5. 키 정책 (Key Policy)
KMS Key는 자체적인 Key Policy 를 가진다 (Resource-based).
"이 키를 누가 쓸 수 있나"
"이 키를 누가 관리할 수 있나" (관리자 / 사용자 분리)
운영에서는 보통
관리자 그룹 → 키 정책 변경, 삭제
서비스 Role → 사용만 (Encrypt / Decrypt)
로 분리한다.
6. 어디에 쓰이는가
| 서비스 | KMS 활용 |
|---|---|
| S3 | SSE-KMS — 객체별 자동 암호화 |
| EBS | 볼륨 암호화 |
| RDS / Aurora | 스토리지 암호화 + 백업 암호화 |
| DynamoDB | 테이블 데이터 + 백업 암호화 |
| Secrets Manager | 시크릿 값 암호화 |
| CloudWatch Logs | 로그 그룹 암호화 |
| Lambda | 환경 변수 암호화 |
| SQS · SNS | 메시지 암호화 (SSE) |
거의 모든 데이터 저장소가 KMS 위에 산다.
7. KMS는 비싸진다 — 호출 횟수
KMS는 호출당 과금이다.
$0.03 / 10,000건 (대략)
작은 비용 같지만 초당 수천 번 호출하면 누적된다.
해법:
- Envelope Encryption (이미 대부분 자동)
- DEK 캐싱 (애플리케이션 측에서 짧게 캐시)
- S3 Bucket Keys (S3 SSE-KMS의 호출 수를 크게 줄임)
8. 우리 서비스에서
[CMK들]
├─ kms/prod-db → RDS · DynamoDB 암호화
├─ kms/prod-storage → S3 버킷 암호화
└─ kms/prod-secrets → Secrets Manager 시크릿
각 키는 자동 회전 ON, 키 정책은 서비스별로 사용 권한 분리
- 사람 관리자: 키 정책 관리
- ECS Task Role: 자기 서비스가 쓰는 키만 Encrypt/Decrypt 허용
9. 직접 확인해보기 — CLI
# CMK 만들기
aws kms create-key \
--description "prod-storage" \
--key-spec SYMMETRIC_DEFAULT
# 자동 회전 켜기
aws kms enable-key-rotation --key-id <key-id>
# 별칭(alias) 만들기 (사람이 기억하기 쉽게)
aws kms create-alias \
--alias-name alias/prod-storage \
--target-key-id <key-id>
# S3 버킷 암호화 적용
aws s3api put-bucket-encryption \
--bucket msa-prod-uploads \
--server-side-encryption-configuration '{
"Rules": [{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "aws:kms",
"KMSMasterKeyID": "alias/prod-storage"
},
"BucketKeyEnabled": true
}]
}'
BucketKeyEnabled: true 가 비용 절감의 핵심.
10. 코드로는 이렇게 생겼다 — Terraform
resource "aws_kms_key" "storage" {
description = "prod-storage"
enable_key_rotation = true
deletion_window_in_days = 30
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "EnableRootAdmin"
Effect = "Allow"
Principal = { AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" }
Action = "kms:*"
Resource = "*"
},
{
Sid = "AllowOrdersTask"
Effect = "Allow"
Principal = { AWS = aws_iam_role.orders_task.arn }
Action = ["kms:Encrypt", "kms:Decrypt", "kms:GenerateDataKey"]
Resource = "*"
}
]
})
}
resource "aws_kms_alias" "storage" {
name = "alias/prod-storage"
target_key_id = aws_kms_key.storage.id
}
resource "aws_s3_bucket_server_side_encryption_configuration" "uploads" {
bucket = aws_s3_bucket.uploads.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
kms_master_key_id = aws_kms_alias.storage.arn
}
bucket_key_enabled = true
}
}
11. 이렇게 쓰면 망한다 — 안티패턴
안티패턴 1. 모든 자원에 같은 키 하나
폭발 반경이 커진다.
도메인/환경/용도별로 키 분리
안티패턴 2. Bucket Keys를 안 켜고 S3에 SSE-KMS
S3 GET 마다 KMS 호출이 발생해 비용이 폭증한다.
안티패턴 3. 키 정책을 너무 넓게
누구나 Decrypt 할 수 있으면 KMS의 의미가 줄어든다.
사용 권한은 서비스 Role 단위로 좁게
안티패턴 4. 자동 회전을 안 켠다
운영 키는 자동 회전을 켜는 게 기본.
12. 한 줄로 정리
KMS는 키를 직접 다루지 않고 안전하게 쓸 수 있게 해주는 도구이며,
저장 중 암호화 + 자동 회전 + 좁은 키 정책 세 가지가 운영의 토대다
13. 이 장의 핵심 정리
- KMS는 키 값을 노출하지 않고 암호화를 제공하는 서비스다.
- 운영 자원은 Customer Managed Key (CMK) 로 옮긴다.
- Envelope Encryption으로 큰 데이터도 효율적으로 처리한다.
- 키 정책으로 관리자 / 사용자 권한을 분리한다.
- S3는 SSE-KMS + Bucket Keys 조합이 표준.
- 자동 회전은 거의 항상 켠다.